package com.ran.java_gobang_new.api;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.ran.java_gobang_new.manager.OnlineManager;
import com.ran.java_gobang_new.manager.RoomManager;
import com.ran.java_gobang_new.my_exception.GameException;
import com.ran.java_gobang_new.pojo.dao.Room;
import com.ran.java_gobang_new.pojo.dao.UserInfo;
import com.ran.java_gobang_new.pojo.request.ChessRequest;
import com.ran.java_gobang_new.pojo.response.ChessResponse;
import com.ran.java_gobang_new.pojo.response.GameReadyResponse;
import com.ran.java_gobang_new.pojo.response.Result;
import com.ran.java_gobang_new.service.GameService;
import com.ran.java_gobang_new.service.UserInfoServise;
import com.ran.java_gobang_new.utils.JsonTrans;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: ran
 * Date: 2025-09-04
 * Time: 17:35
 */
@Component
@Slf4j
public class GameAPI extends TextWebSocketHandler {

    @Autowired
    private OnlineManager onlineManager;
    @Autowired
    private RoomManager roomManager;

    // 进入游戏房间建立连接后
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 判断当前用户是否登录
        // 判断用户是否是双开进入的游戏房间
        // 两个用户都准备好了, 都建立完连接了, 要告诉双方, 都准备完毕
        UserInfo userInfo = (UserInfo) session.getAttributes().get("user");
        if (userInfo == null) {
            log.error("玩家未登录直接跳转到游戏房间!");
            session.sendMessage(JsonTrans.trans(Result.fail("禁止玩家未登录直接跳转到游戏房间!")));
            throw new GameException("玩家未登录进入游戏房间连接异常");
        }

        if (onlineManager.getHallSession(userInfo.getUserId()) != null || onlineManager.getRoomSession(userInfo.getUserId()) != null) {
            log.info("玩家: " + userInfo.getUserName() + " 双开, 既登录大厅又登录游戏房间");
            session.sendMessage(JsonTrans.trans(Result.fail("禁止玩家未登录直接跳转到游戏房间!")));
            throw new GameException("禁止双开!");
        }

        Room room = roomManager.getRoomByUserId(userInfo.getUserId());
        // 加入游戏房间在线的状态
        onlineManager.addRoom(userInfo.getUserId(), session);
        log.info("玩家: " + userInfo.getUserName() + " 进入游戏房间");
        synchronized (room) {
            // 添加玩家1,2 的信息
            if (room == null) {
                // 说明没有匹配到房间
                throw new GameException("没有正确匹配到房间");
            }
            // 当前第一个连接的玩家为空时, 设置为 先手, 并给房间玩家 userid 赋值
            if (room.getUser1() == null) {
                room.setUser1(userInfo);
                room.setWhite(userInfo.getUserId());
                return;
            }
            if (room.getUser2() == null) {
                room.setUser2(userInfo);
                // 设置完成 玩家2 后, 通知所有用户已准备好了, 对手是谁都发送过去

                /*通知玩家1, thisUser 就是 玩家1*/
                notifyReady(room, room.getUser1(), room.getUser2());
                /*通知玩家2, thisUser 就是 玩家2*/
                notifyReady(room, room.getUser2(), room.getUser1());
                return;
            }
        }

        // 按道理如果有第三个人连接到这个房间, 那么应该是非法连接
        // 从房间在线管理中删除
        onlineManager.removeRoom(userInfo.getUserId());

        // 两个人时, 就应该阻止其他人再进入房间, 返回一些信息
        GameReadyResponse response = new GameReadyResponse();
        response.setOk(false);
        response.setErrMsg("该房间已满!");
        // 发送给前端
        session.sendMessage(JsonTrans.trans(response));

    }

    private void notifyReady(Room room, UserInfo thisUser, UserInfo thatUser) throws IOException {
        // 获取当前用户的 Session, 要做的是发给当前用户这个信息
        WebSocketSession session = onlineManager.getRoomSession(thisUser.getUserId());
        GameReadyResponse response = new GameReadyResponse();
        response.setOk(true);
        response.setRoomId(room.getUUID());
        response.setThisUser(thisUser);
        response.setThatUser(thatUser);
        response.setWhite(room.getWhite());
        session.sendMessage(JsonTrans.trans(response));
    }

    // 接收前端游戏房间发送的信息
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        UserInfo userInfo = (UserInfo) session.getAttributes().get("user");
        if (userInfo == null) {
            return;
        }
        // 把前端发送的信息转化为 落子请求
        ChessRequest chessRequest = JsonTrans.transChessRequest(message);
        if (chessRequest.getChess() && chessRequest.getUserId() != null) {
            // 调用落子请求的方法

            Room room = roomManager.getRoomByUserId(chessRequest.getUserId());
            room.gameService.putChess(chessRequest,chessRequest.getRow(),chessRequest.getCol());

            // 游戏的获胜结果, 放到了 gameService 返回响应
        }else {
            GameReadyResponse response = new GameReadyResponse();
            response.setOk(false);
            response.setErrMsg("下棋的响应异常!");
            session.sendMessage(JsonTrans.trans(response));
        }

    }


    // 与游戏房间连接异常终止
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        try {
            UserInfo userInfo = (UserInfo) session.getAttributes().get("user");
            if (userInfo == null) {
                return;
            }
            WebSocketSession thisUserSession = onlineManager.getRoomSession(userInfo.getUserId());
            if (session == thisUserSession) {
                onlineManager.removeRoom(userInfo.getUserId());
            }
            notifyThatUserWinner(userInfo);
        }catch (NullPointerException e) {
            throw new GameException("GameAPI 的空指针异常");
        }
    }

    @Autowired
    private UserInfoServise userInfoServise;
    private void notifyThatUserWinner(UserInfo userInfo) throws IOException {
        Room room = roomManager.getRoomByUserId(userInfo.getUserId());
        // 查看房间是否正常销毁
        if (room == null) {
            log.info("房间正常销毁");
            return;
        }

        log.info("非正常销毁房间, 已自动回收房间!");
        roomManager.remove(room,room.getUser1().getUserId(),room.getUser2().getUserId());

        // 判断对手是否也掉线
        UserInfo thatUser = userInfo == room.getUser1() ? room.getUser2() : room.getUser1();
        WebSocketSession roomSession = onlineManager.getRoomSession(thatUser.getUserId());
        if (roomSession == null) {
            // 对手也掉线, 那么不用返回任何东西
            log.info("对手 "+thatUser.getUserName()+" 也掉线");
            onlineManager.removeRoom(thatUser.getUserId());
            return;
        }
        ChessResponse response = new ChessResponse();
        response.setChess(true);
        response.setFlag(true);
        response.setWinner(thatUser.getUserId());
        response.setUserId(thatUser.getUserId());
        roomSession.sendMessage(JsonTrans.trans(response));

        // 更新玩家信息
        userInfoServise.win(thatUser.getUserId());
        userInfoServise.lose(userInfo.getUserId());
        // 释放在线状态
        onlineManager.removeRoom(thatUser.getUserId());

    }


    // 与游戏房间连接正常断开
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        try {
            UserInfo userInfo = (UserInfo) session.getAttributes().get("user");
            if (userInfo == null) {
                return;
            }
            WebSocketSession thisUserSession = onlineManager.getRoomSession(userInfo.getUserId());
            if (session == thisUserSession) {
                onlineManager.removeRoom(userInfo.getUserId());
            }
            notifyThatUserWinner(userInfo);

//            Room room = roomManager.getRoomByUserId(userInfo.getUserId());
//            roomManager.remove(room,room.getUser1().getUserId(),room.getUser2().getUserId());
//            GameReadyResponse response = new GameReadyResponse();
//            response.setOk(false);
//            response.setErrMsg("与游戏房间连接异常终止");
//            session.sendMessage(JsonTrans.trans(response));
        }catch (NullPointerException e) {
            throw new GameException("GameAPI 的空指针异常");
        }

    }
}
